package com.feilong.servlet.http;

import java.math.BigDecimal;
import java.net.URI;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.feilong.commons.core.Constants;
import com.feilong.commons.core.enumeration.CharsetType;
import com.feilong.commons.core.net.URIUtil;
import com.feilong.commons.core.util.ObjectUtil;
import com.feilong.commons.core.util.StringUtil;
import com.feilong.commons.core.util.Validator;

/**
 * 处理参数相关
 * 
 * @author 金鑫 2010-4-15 下午04:01:29
 */
public final class ParamUtil{

	private ParamUtil(){}

	/**
	 * 请求路径中是否包含某个参数名称 (注意:这是判断是否包含参数,而不是判断参数值是否为空)
	 * 
	 * <pre>
	 * 如果传递来的param为null或者&quot;&quot;.则返回false
	 * 
	 * </pre>
	 * 
	 * @param request
	 *            请求
	 * @param param
	 *            参数名称
	 * @return 包含该参数返回true,不包含返回false
	 */
	public static boolean isContainsParam(HttpServletRequest request,String param){
		boolean flag = false;
		if (Validator.isNotNullOrEmpty(param)){
			@SuppressWarnings("unchecked")
			Enumeration<String> enumeration = request.getParameterNames();
			String p_name = null;
			while (enumeration.hasMoreElements()){
				p_name = enumeration.nextElement().toString();
				if (param.equals(p_name)){
					flag = true;
				}
			}
		}
		return flag;
	}

	/**
	 * 请求路径中是否包含某个参数名称 (注意:这是判断是否包含参数,而不是判断参数值是否为空)
	 * 
	 * @param request
	 *            请求
	 * @param param
	 *            参数名称
	 * @return 不包含该参数返回true
	 */
	public static boolean isNotContainsParam(HttpServletRequest request,String param){
		return !isContainsParam(request, param);
	}

	/**
	 * 是否包含参数
	 * 
	 * @param request
	 *            请求
	 * @return 包含返回true
	 */
	public static boolean isContainsParam(HttpServletRequest request){
		return StringUtil.isContain(RequestUtil.getRequestAllURL(request), "?");
	}

	/**
	 * 不包含参数
	 * 
	 * @param request
	 * @return 不包含参数
	 */
	public static boolean isNotContainsParam(HttpServletRequest request){
		return !isContainsParam(request);
	}

	/**
	 * 获得参数经过8859之后的值
	 * 
	 * @param request
	 *            当前请求
	 * @param param
	 *            参数名称
	 * @return 获得参数经过8859之后的值
	 * @deprecated 暂没有想好
	 */
	public static String getParameterWith8859(HttpServletRequest request,String param){
		String value = getParameter(request, param);
		return URIUtil.decodeLuanMa_ISO8859(value);
	}

	/**
	 * 将参数值转换成int类型
	 * 
	 * @param request
	 *            请求
	 * @param paramName
	 *            参数名称
	 * @return 将参数值转换成int类型
	 */
	public static Integer getParameterToInteger(HttpServletRequest request,String paramName){
		String value = getParameter(request, paramName);
		return ObjectUtil.toInteger(value);
	}

	/**
	 * 将参数值转换成BigDecimal类型
	 * 
	 * @param request
	 *            请求
	 * @param paramName
	 *            参数名称
	 * @return 将参数值转换成BigDecimal类型
	 */
	public static BigDecimal getParameterToBigDecimal(HttpServletRequest request,String paramName){
		String value = getParameter(request, paramName);
		return ObjectUtil.toBigDecimal(value);
	}

	/**
	 * 获得request中的请求参数值
	 * 
	 * @param request
	 *            当前请求
	 * @param paramName
	 *            参数名称
	 * @return 获得request中的请求参数值
	 */
	public static String getParameter(HttpServletRequest request,String paramName){
		return request.getParameter(paramName);
	}

	/**
	 * 参数值去除井号,一般用于sendDirect 跳转中带有#标签,参数值取不准确的问题
	 * 
	 * @param request
	 * @param paramName
	 * @return 参数值去除井号,一般用于sendDirect 跳转中带有#标签,参数值取不准确的问题
	 */
	public static String getParameterWithoutSharp(HttpServletRequest request,String paramName){
		String returnValue = getParameter(request, paramName);
		if (Validator.isNotNullOrEmpty(returnValue)){
			if (StringUtil.isContain(returnValue, "#")){
				returnValue = StringUtil.substring(returnValue, null, "#");
			}
		}
		return returnValue;
	}

	/**
	 * 原样获得参数值(request.getParameter()函数时，会自动进行一次URI的解码过程，调用时内置的解码过程会导致乱码出现)
	 * 
	 * <pre>
	 * url参数是什么,取到的就是什么,不经过处理
	 * </pre>
	 * 
	 * @param request
	 *            请求
	 * @param paramName
	 *            参数名称
	 * @return 原样获得参数值
	 */
	public static String getParameterAsItIsDecode(HttpServletRequest request,String paramName){
		String returnValue = null;
		String queryString = request.getQueryString();
		if (Validator.isNotNullOrEmpty(queryString)){
			Map<String, String> map = convertParametersToMap(queryString, Constants.bianma);
			return map.get(paramName);
		}
		return returnValue;
	}

	/**
	 * FormatHTML取到参数值,通常处理文本域里的换行问题
	 * 
	 * @param request
	 * @param paramName
	 *            参数名称
	 * @return FormatHTML取到参数值,通常处理文本域里的换行问题
	 */
	public static String getParameterWithFormatHTML(HttpServletRequest request,String paramName){
		String returnValue = getParameter(request, paramName);
		returnValue = returnValue.replace("\r\n", "<br/>");// 换行
		return returnValue;
	}

	/**
	 * 取到参数值,没有返回null,有去除空格返回
	 * 
	 * @param request
	 *            当前请求
	 * @param paramName
	 * @return 取到参数值,没有返回null,有去除空格返回
	 */
	public static String getParameterWithTrim(HttpServletRequest request,String paramName){
		String returnValue = getParameter(request, paramName);
		if (Validator.isNotNullOrEmpty(returnValue)){
			returnValue = returnValue.trim();
		}
		return returnValue;
	}

	/**
	 * 将a=1&b=2这样格式的数据转换成map
	 * 
	 * @param parameters
	 *            a=1&b=2类型的数据
	 * @param bianma
	 *            何种编号,可以为null或者"",表示不使用编码处理
	 * @return map value的处理
	 *         <ul>
	 *         <li>没有Validator.isNullOrEmpty(bianma) 那么就原样返回</li>
	 *         <li>如果有编码,使用 编码解析值URIUtil.decode(value, bianma)</li>
	 *         </ul>
	 */
	public static Map<String, String> convertParametersToMap(String parameters,String bianma){
		if (Validator.isNotNullOrEmpty(parameters)){
			String[] parametersArray = parameters.split("&");
			if (Validator.isNotNullOrEmpty(parametersArray)){
				Map<String, String> map = new LinkedHashMap<String, String>();
				String keyAndValue;
				String[] tempArray;
				for (int i = 0, j = parametersArray.length; i < j; ++i){
					keyAndValue = parametersArray[i];
					tempArray = keyAndValue.split("=", 2);
					if (tempArray != null && tempArray.length == 2){
						String key = tempArray[0];
						String value = tempArray[1];
						// 没有编码 那么就原样返回
						if (Validator.isNullOrEmpty(bianma)){
							map.put(key, value);
						}
						// 如果有编码,使用 编码解析值
						else{
							map.put(key, URIUtil.decode(value, bianma));
						}
					}
				}
				return map;
			}
		}
		return null;
	}

	// ******************************************************************************************

	/**
	 * 添加参数 加入含有该参数会替换掉
	 * 
	 * @param url
	 * @param paramName
	 *            添加的参数名称
	 * @param parameValue
	 *            添加的参数名称
	 * @return 添加参数 加入含有该参数会替换掉
	 */
	public static String addParameter(String url,String paramName,Object parameValue,String charsetType){
		URI uri = URI.create(url);
		return addParameter(uri, paramName, parameValue, charsetType);
	}

	/**
	 * 添加参数 加入含有该参数会替换掉<br>
	 * 默认使用CharsetType.UTF8解析参数
	 * 
	 * @param url
	 * @param paramName
	 *            添加的参数名称
	 * @param parameValue
	 *            添加的参数名称
	 * @return 添加参数 加入含有该参数会替换掉
	 * @deprecated 请使用{@link #addParameter(String, String, Object, String)} 代替
	 */
	public static String addParameter(String url,String paramName,Object parameValue){
		String charsetType = CharsetType.UTF8;
		return addParameter(url, paramName, parameValue, charsetType);
	}

	/**
	 * 添加参数 加入含有该参数会替换掉
	 * 
	 * @param uri
	 *            URI 统一资源标识符 (URI),<br>
	 *            如果带有? 和参数,会先被截取,最后再拼接,<br>
	 *            如果不带?,则自动 增加?
	 * @param nameAndValueMap
	 *            nameAndValueMap param name 和value 的键值对
	 * @return 添加参数 加入含有该参数会替换掉
	 * @exception 如果FeiLongValidator.isNull
	 *                (nameAndValueMap) 则IllegalArgumentException
	 */
	public static String addParameter(String url,Map<String, Object> nameAndValueMap,String charsetType){
		URI uri = URI.create(url);
		return addParameter(uri, nameAndValueMap, charsetType);
	}

	/**
	 * 添加参数 加入含有该参数会替换掉 <br>
	 * 默认使用CharsetType.UTF8解析参数
	 * 
	 * @param uri
	 * @param paramName
	 *            添加的参数名称
	 * @param parameValue
	 *            添加的参数名称
	 * @return
	 */
	public static String addParameter(URI uri,String paramName,Object parameValue){
		String charsetType = CharsetType.UTF8;
		return addParameter(uri, paramName, parameValue, charsetType);
	}

	/**
	 * 添加参数 加入含有该参数会替换掉
	 * 
	 * @param uri
	 *            URI 统一资源标识符 (URI),<br>
	 *            如果带有? 和参数,会先被截取,最后再拼接,<br>
	 *            如果不带?,则自动 增加?
	 * @param paramName
	 *            添加的参数名称
	 * @param parameValue
	 *            添加的参数名称
	 * @param charsetType
	 *            编码
	 * @return 添加参数 加入含有该参数会替换掉
	 */
	public static String addParameter(URI uri,String paramName,Object parameValue,String charsetType){
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(paramName, parameValue);
		return addParameter(uri, map, charsetType);
	}

	/**
	 * 添加参数 加入含有该参数会替换掉
	 * 
	 * @param uri
	 *            URI 统一资源标识符 (URI),<br>
	 *            如果带有? 和参数,会先被截取,最后再拼接,<br>
	 *            如果不带?,则自动 增加?
	 * @param nameAndValueMap
	 *            nameAndValueMap param name 和value 的键值对
	 * @param charsetType
	 *            编码
	 * @return 添加参数 加入含有该参数会替换掉
	 * @exception 如果FeiLongValidator.isNull
	 *                (nameAndValueMap) 则IllegalArgumentException
	 */
	public static String addParameter(URI uri,Map<String, Object> nameAndValueMap,String charsetType){
		if (Validator.isNullOrEmpty(nameAndValueMap)){
			throw new IllegalArgumentException("nameAndValueMap can not be null!");
		}
		// ***********************************************************************
		String url = uri.toString();
		String before = getBefore(url);
		// ***********************************************************************
		// 返回此 URI 的原始查询组成部分。 URI 的查询组成部分（如果定义了）只包含合法的 URI 字符。
		String query = uri.getRawQuery();
		// ***********************************************************************
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		// 传入的url不带参数的情况
		if (Validator.isNullOrEmpty(query)){
			// not to do
		}else{
			Map<String, String> originalMap = convertParametersToMap(query, charsetType);
			map.putAll(originalMap);
		}
		map.putAll(nameAndValueMap);
		// **************************************************************
		return toUrl(before, map);
	}

	/**
	 * 删除参数
	 * 
	 * @param url
	 * @param paramName
	 * @param charsetType
	 *            编码
	 * @return
	 */
	public static String removeParameter(String url,String paramName,String charsetType){
		URI uri = URI.create(url);
		return removeParameter(uri, paramName, charsetType);
	}

	/**
	 * 删除参数
	 * 
	 * @param uri
	 * @param paramName
	 * @param charsetType
	 *            编码
	 * @return
	 */
	private static String removeParameter(URI uri,String paramName,String charsetType){
		List<String> paramNameList = null;
		if (Validator.isNotNullOrEmpty(paramName)){
			paramNameList = new ArrayList<String>();
			paramNameList.add(paramName);
		}
		return removeParameter(uri, paramNameList, charsetType);
	}

	/**
	 * 删除参数
	 * 
	 * @param url
	 * @param paramNameList
	 * @param charsetType
	 *            编码
	 * @return
	 */
	public static String removeParameter(String url,List<String> paramNameList,String charsetType){
		URI uri = URI.create(url);
		return removeParameter(uri, paramNameList, charsetType);
	};

	/**
	 * 删除参数
	 * 
	 * @param uri
	 * @param paramNameList
	 * @param charsetType
	 *            编码
	 * @return
	 */
	public static String removeParameter(URI uri,List<String> paramNameList,String charsetType){
		String url = uri.toString();
		// 如果 paramNameList 是null 原样返回
		if (Validator.isNullOrEmpty(paramNameList)){
			return url;
		}
		// ***********************************************************************
		String before = getBefore(url);
		// ***********************************************************************
		// 返回此 URI 的原始查询组成部分。 URI 的查询组成部分（如果定义了）只包含合法的 URI 字符。
		String query = uri.getRawQuery();
		// ***********************************************************************
		// 传入的url不带参数的情况
		if (Validator.isNullOrEmpty(query)){
			// 不带参数原样返回
			return url;
		}else{
			Map<String, String> map = convertParametersToMap(query, charsetType);
			for (String paramName : paramNameList){
				map.remove(paramName);
			}
			return toUrl(before, map);
		}
	}

	/**
	 * url里面仅保留 指定的参数
	 * 
	 * @param url
	 * @param paramNameList
	 * @param charsetType
	 *            编码
	 * @return
	 */
	public static String retentionParams(String url,List<String> paramNameList,String charsetType){
		URI uri = URI.create(url);
		return retentionParams(uri, paramNameList, charsetType);
	}

	/**
	 * url里面仅保留 指定的参数<br>
	 * 默认使用utf-8
	 * 
	 * @param url
	 * @param paramNameList
	 * @return
	 * @deprecated 请使用带参数 {@link #retentionParams(String, List, String)} 代替
	 */
	public static String retentionParams(String url,List<String> paramNameList){
		String charsetType = CharsetType.UTF8;
		return retentionParams(url, paramNameList, charsetType);
	}

	/**
	 * url里面仅保留 指定的参数
	 * 
	 * @param uri
	 * @param paramNameList
	 * @param charsetType
	 *            编码
	 * @return
	 */
	public static String retentionParams(URI uri,List<String> paramNameList,String charsetType){
		String url = uri.toString();
		// 如果 paramNameList 是null 原样返回
		if (Validator.isNullOrEmpty(paramNameList)){
			return url;
		}
		String before = getBefore(url);
		// ***********************************************************************
		// 返回此 URI 的原始查询组成部分。 URI 的查询组成部分（如果定义了）只包含合法的 URI 字符。
		String query = uri.getRawQuery();
		// ***********************************************************************
		// 传入的url不带参数的情况
		if (Validator.isNullOrEmpty(query)){
			// 不带参数原样返回
			return url;
		}else{
			Map<String, Object> map = new LinkedHashMap<String, Object>();
			Map<String, String> originalMap = convertParametersToMap(query, charsetType);
			for (String paramName : paramNameList){
				map.put(paramName, originalMap.get(paramName));
			}
			return toUrl(before, map);
		}
	}

	/**
	 * 拼接url
	 * 
	 * @param before
	 *            ?前面的部分
	 * @param map
	 *            参数map
	 * @return
	 */
	public static String toUrl(String before,Map<String, ?> map){
		StringBuilder builder = new StringBuilder("");
		builder.append(before);
		// map 不是空 表示 有参数
		if (Validator.isNotNullOrEmpty(map)){
			builder.append("?");
			for (Map.Entry<String, ?> entry : map.entrySet()){
				builder.append(entry.getKey());
				builder.append("=");
				builder.append(entry.getValue());
				builder.append("&");
			}
			// 把最后一个多的& 截取掉
			return builder.toString().substring(0, builder.toString().length() - 1);
		}
		return builder.toString();
	}

	/**
	 * ?前面的连接
	 * 
	 * @param url
	 * @return
	 */
	private static String getBefore(String url){
		String before = "";
		// 判断url中是否含有?
		int index = url.indexOf('?');
		if (index == -1){
			before = url;
		}else{
			before = url.substring(0, index);
		}
		return before;
	}

	// /**
	// * 取到参数值,参数解密
	// *
	// * @param request
	// * @param paramName
	// * 参数名称
	// * @return 取到参数值,参数解密
	// */
	// public static String getParameterWithDecrypt(HttpServletRequest request,String paramName){
	// String returnValue = getParameter(request, paramName);
	// if (Validator.isNotNullOrEmpty(returnValue)){
	// returnValue = FeiLongSecurity.getDecryptParam(returnValue);
	// }
	// return returnValue;
	// }

	// /**
	// * 取到参数值,参数解密,并且转成BigDecimal类型
	// *
	// * <pre>
	// * 调用了getParameterWithDecrypt(HttpServletRequest request,String paramName)方法
	// * </pre>
	// *
	// * @param request
	// * @param paramName
	// * 参数名称
	// * @return 取到参数值,参数解密,并且转成BigDecimal类型
	// */
	// public static BigDecimal getParameterWithDecryptAndToBigDecimal(HttpServletRequest request,String paramName){
	// String returnValue = getParameterWithDecrypt(request, paramName);
	// if (Validator.isNotNullOrEmpty(returnValue)){
	// return ObjectUtil.toBigDecimal(returnValue);
	// }
	// return null;
	// }

	// /**
	// * 获得值对应的文字说明
	// *
	// * @param valueAndTexts
	// * 值和文字组成的键值对 以&拼接 如"1=男&0=女"
	// * @param value
	// * 值
	// * @return Text
	// */
	// public static String getText(String valueAndTexts,Object value){
	// String returnValue = null;
	// if (Validator.isNotNullOrEmpty(value)){
	// Map<String, String> map = convertParametersToMap(valueAndTexts, null);
	// for (Map.Entry<String, String> entry : map.entrySet()){
	// if (entry.getKey().equals(value.toString())){
	// returnValue = entry.getValue();
	// break;
	// }
	// }
	// return returnValue;
	// }
	// return returnValue;
	// }

	// /**
	// * 获得性别的文字 默认1=男&0=女
	// *
	// * @param value
	// * 值
	// * @return 获得性别的文字 默认1=男&0=女
	// */
	// public static String getSexNameDefault(Object value){
	// return getText("1=男&0=女", value);
	// }

	// /**
	// * 婚姻状况 1=已婚&2=未婚&3=保密
	// *
	// * @param value
	// * value
	// * @return 婚姻状况 1=已婚&2=未婚&3=保密
	// */
	// public static String getMarriageStateDefault(Object value){
	// return getText("1=已婚&2=未婚&3=保密", value);
	// }
}
